home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 October: Mac OS SDK / Dev.CD Oct 97 SDK2.toast / Development Kits (Disc 2) / Thread Manager / Sample Applications / Power Examples / ThreadedSort / Sprocket / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1994-11-22  |  10.0 KB  |  383 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.          <5>    11/16/94    DRF        Added explicit #include <SegLoad.h> for latest universal
  15.                                     headers. Also added cast to keep MPW CFront happier.
  16.          <4>    11/16/94    DRF        Add StdFilterProc for THINK C.
  17.          <3>     9/27/94    DRF         AppLib.h is now Sprocket.h
  18.          <2>      9/9/94    DRF        Reordered headers and removed redundant #includes.
  19.  */
  20.  
  21. #include "Sprocket.h"
  22.  
  23. #include <Fonts.h>
  24. #include <Resources.h>
  25. #include <TextUtils.h>
  26. #include <Threads.h>        //    For YieldToAnyThread()
  27. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  28. #include <SegLoad.h>        //    For ExitToShell()
  29.  
  30. //    Some types which should probably be defined in <Dialogs.h>
  31. //    NOTE: These must be aligned on 2-byte boundaries
  32. #if defined(powerc) || defined (__powerc)
  33. #pragma options align=mac68k
  34. #endif
  35.  
  36. struct DialogItem
  37.     {
  38.     long    usedByDialogManager;
  39.     Rect    boundsRect;
  40.     char    type;
  41.     char    length;
  42.     };
  43.  
  44. struct DialogItemList            //    a.k.a. a 'DITL'
  45.     {
  46.     short        count;
  47.     DialogItem    firstItem[1];
  48.     };
  49.  
  50. //    Restore default alignment
  51. #if defined(powerc) || defined(__powerc)
  52. #pragma options align=reset
  53. #endif
  54.  
  55. typedef    DialogItem        *DialogItemPtr;
  56. typedef    DialogItemList    **DialogItemListHandle;
  57. typedef    DialogTemplate    **DialogTemplateHandle;
  58.  
  59. #ifndef    powerc
  60. #ifdef    __SC__
  61.  
  62. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  63.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  64.  
  65. pascal Boolean
  66. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  67.     {
  68.     ModalFilterUPP    filterUPP;
  69.  
  70.     //    Dialogs.h
  71.     
  72.     (void) GetStdFilterProc(&filterUPP);
  73.  
  74.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  75.     }
  76.  
  77. #endif
  78. #endif
  79.  
  80. //    private function Prototypes
  81.  
  82. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  83. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  84. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  85. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  86.  
  87.  
  88.  
  89. ///////////////////////////////////////////////////////////
  90. //
  91. //    StandardAlert
  92. //
  93. //    An alternative to Alert() which uses the extended
  94. //    Dialog Manager capabilities.
  95. //
  96. //    I’m not sure we really need this call, but it seems
  97. //    to do the trick just fine.
  98.  
  99. short
  100. StandardAlert(    short dlogID,
  101.                 short defaultItem,                /* = ok */
  102.                 short cancelItem,                /* = 0 */
  103.                 ModalFilterUPP customFilterProc    /* = nil */)
  104.     {
  105.     DialogPtr        theDialog;
  106.     short            itemHit = 0;
  107.     ModalFilterUPP    filterToUse;
  108.     
  109.     HiliteWindowsForModalDialog(false);
  110.  
  111.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  112.     if (defaultItem)
  113.         SetDialogDefaultItem(theDialog,defaultItem);
  114.     if (cancelItem)
  115.         SetDialogCancelItem(theDialog,cancelItem);
  116.  
  117.     if (customFilterProc)
  118.         filterToUse = customFilterProc;
  119.     else
  120.         filterToUse = StandardDialogFilter;
  121.  
  122.     do
  123.         ModalDialog(filterToUse,&itemHit);
  124.     while (itemHit == 0);
  125.     
  126.     DisposeDialog(theDialog);
  127.  
  128.     HiliteWindowsForModalDialog(true);
  129.  
  130.     return itemHit;
  131.     }
  132.  
  133.  
  134. ///////////////////////////////////////////////////////////
  135. //
  136. //    ErrorAlert
  137. //
  138. //    A nice error reporting routine which presents an
  139. //    auto-sized alert box containing the supplied text.
  140. //
  141. //    NOTE:    This routine ASSUMES the following 'DITL'
  142. //            structure:
  143. //
  144. //            item #1 : an “OK” button
  145. //            item #2 : a static text item, somewhere above #1
  146. //
  147. //    NOTE:    We probably need to worry more about low
  148. //            memory conditions-- this can probably
  149. //            be handled by a custom GrowZoneProc and
  150. //            reserve memory area large enough to hold
  151. //            all the space we’d need.
  152. //
  153.  
  154. void
  155. ErrorAlert(short stringList,short whichString)
  156.     {
  157.     Str255                    errorString;
  158.     GrafPtr                    oldPort,windowMgrPort;
  159.     short                    oldFont;
  160.     DialogTemplateHandle    errorDialogTemplate;
  161.     DialogItemListHandle    errorDialogItems;
  162.     TEHandle                aTEHandle;
  163.     Rect                    textRect;
  164.     short                    textHeight;
  165.     short                    additionalSpaceNeeded;
  166.     DialogItemPtr            okButtonItem,errorTextItem;
  167.     const StringPtr            nullStr = (StringPtr) "\p";
  168.  
  169.     GetIndString(errorString,stringList,whichString);
  170.     
  171.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  172.     HLock((Handle) errorDialogTemplate);
  173.     
  174.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  175.     HLock((Handle) errorDialogItems);
  176.     
  177.     //    Find the dialog items
  178.     
  179.     okButtonItem = (**errorDialogItems).firstItem;
  180.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  181.     
  182.     GetPort(&oldPort);
  183.     GetWMgrPort(&windowMgrPort);
  184.     SetPort(windowMgrPort);
  185.     oldFont = qd.thePort->txFont;
  186.     TextFont(systemFont);
  187.  
  188.     aTEHandle = TENew(&textRect,&textRect);
  189.     TESetText(&errorString[1],errorString[0],aTEHandle);
  190.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  191.     TEDispose(aTEHandle);
  192.  
  193.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  194.                             - errorTextItem->boundsRect.top);
  195.  
  196.     if (additionalSpaceNeeded > 0)
  197.         {
  198.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  199.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  200.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  201.         }
  202.         
  203.     TextFont(oldFont);
  204.     SetPort(oldPort);
  205.     
  206.     InitCursor();
  207.     ParamText(errorString,nullStr,nullStr,nullStr);
  208.  
  209.     (void) StandardAlert(kErrorAlertID);
  210.  
  211.     ReleaseResource((Handle) errorDialogTemplate);
  212.     ReleaseResource((Handle) errorDialogItems);
  213.     }
  214.  
  215.  
  216. ///////////////////////////////////////////////////////////
  217. //
  218. //    FatalErrorAlert
  219. //
  220. //    A companion to ErrorAlert which also kills the process.
  221. //
  222.  
  223. void
  224. FatalErrorAlert(short stringList,short whichString)
  225.     {
  226.     ErrorAlert(stringList,whichString);
  227.     ExitToShell();
  228.     }
  229.  
  230.  
  231. ///////////////////////////////////////////////////////////
  232. //
  233. //    StandardDialogFilter and StandardDialogFilterYD
  234. //
  235. //    These function takes care of routing events not meant
  236. //    for the dialog window to other parts of the application.
  237. //
  238. //    Use them as an alternative to passing a NIL ModalFilterProc
  239. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  240. //    filter, these routines properly processes update events
  241. //    to keep background processes running.
  242. //
  243. //    The Thread Manager, if present, is also called to yield
  244. //    control to other cooperative threads within the process.
  245. //
  246. //    Because of pascal calling conventions we need two separate
  247. //    routines, but this is minimized by sharing implementation
  248. //    in FilterProcCommon.
  249. //
  250.  
  251. ModalFilterUPP    StandardDialogFilter
  252. = NewModalFilterProc(StandardDialogFilterProc);
  253.  
  254. ModalFilterYDUPP    StandardDialogFilterYD
  255. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  256.  
  257. ModalFilterUPP    StandardCloseDialogFilter
  258. = NewModalFilterProc(StandardCloseDialogFilterProc);
  259.  
  260.  
  261. pascal Boolean
  262. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  263.     {
  264.     //    Call through common code to check for events we’d like to handle.
  265.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  266.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  267.  
  268.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  269.         return true;
  270.     else
  271.         return (StdFilterProc(theDialog, anEvent, itemHit));
  272.     }
  273.  
  274.  
  275. pascal Boolean
  276. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  277.     {
  278.     //    We don’t call through to StdFilterProc since the
  279.     //    Standard File Package already does everything we need.
  280.  
  281.     return FilterProcCommon(theDialog, anEvent, itemHit);
  282.     }
  283.  
  284. void
  285. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  286.     {
  287.     Handle    itemHandle;
  288.     Rect    itemBox;
  289.     long    finalTicks;
  290.     short    itemType;
  291.     
  292.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  293.  
  294.     HiliteControl((ControlHandle) itemHandle,inButton);
  295.     Delay(8,&finalTicks);
  296.     HiliteControl((ControlHandle) itemHandle,0);
  297.     }
  298.  
  299.  
  300. pascal Boolean
  301. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  302.     {
  303.     if ((anEvent->what == keyDown))
  304.         {
  305.         char    c = (char) anEvent->message & charCodeMask;
  306.         
  307.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  308.             {
  309.             *itemHit = kDontSaveDocument;
  310.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  311.             return true;
  312.             }
  313.         }
  314.  
  315.     //    Return through the common code above so that default item processing can happen
  316.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  317.     }
  318.  
  319.  
  320. Boolean
  321. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  322.     {
  323.     switch (anEvent->what)
  324.         {
  325.         case updateEvt:
  326.         case activateEvt:
  327.             //     Update or activate for the dialog window?
  328.             if (theDialog == (DialogPtr) anEvent->message)
  329.                 break;
  330.  
  331.             //    no, fall through to HandleEvent            
  332.             
  333.         case diskEvt:
  334.             HandleEvent(anEvent);
  335.             return(false);
  336.  
  337.         default:
  338.             break;        
  339.         }
  340.  
  341.     if (gHasThreadManager)        //    If we have threads, let them run!
  342.         YieldToAnyThread();
  343.  
  344.     return false;                //    We didn’t handle the event
  345.     }
  346.  
  347.  
  348. //////////////////////////////////////////////////////////////////
  349. //
  350. //    StandardCloseDocument
  351. //
  352. //    Provides the standard human interface for closing a document
  353. //
  354. //    NOTE: When we make TDocument class, this will become a method
  355. //          and probably won’t need any parameters.
  356. //
  357. //    NOTE:    StandardCloseResult matches the dialog items for 
  358.  
  359. StandardCloseResult
  360. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  361.                       Boolean hasNewEditions, Boolean quitting)
  362.     {
  363.     short        whichAlert;
  364.     short        whichString;
  365.     StringPtr    nullStr = (StringPtr) "\p";
  366.     Str255        reasonForClosingStr;
  367.  
  368.     if (hasNewEditions)
  369.         whichAlert = kStandardCloseWithNewPubsAlertID;
  370.     else
  371.         whichAlert = kStandardCloseAlertID;
  372.     
  373.     if (quitting)
  374.         whichString = kQuittingStr;
  375.     else
  376.         whichString = kClosingStr;
  377.  
  378.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  379.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  380.     
  381.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  382.     }
  383.